package gorpc

import (
	"errors"
	"fmt"
	"time"
)

// Common callback errors
var (
	ErrNotImplemented = errors.New("method not implemented")
	ErrInvalidMessage = errors.New("invalid message")
)

// RPCCallback defines the interface for RPC event callbacks
type RPCCallback interface {
	// OnNotify is called when a notification is received
	// Equivalent to onRpcIssue in C++
	OnNotify(session *RPCSession, msg *RPCMessage)

	// OnRequest is called when a request is received and needs to be processed
	// Equivalent to onRpcCallMethod in C++
	// Returns response data and error if any
	OnRequest(session *RPCSession, inMsg *RPCMessage, outMsg *RPCMessage, timeout time.Duration) error

	// OnConnect is called when a new session is established
	// Equivalent to onRpcConnected in C++
	OnConnect(session *RPCSession)

	// OnClose is called when a session is closed
	// Equivalent to onRpcClosed in C++
	// errorCode: error code indicating the reason for closure
	// errorMsg: detailed error message
	OnClose(session *RPCSession, errorCode int, errorMsg string)
}

// BaseCallback provides a default implementation of RPCCallback
// It can be embedded in custom callback implementations to avoid implementing all methods
type BaseCallback struct {
	// Optional fields for customization
	DefaultTimeout time.Duration // Default timeout for request handling
	LogEnabled     bool          // Whether to log callback events
}

// NewBaseCallback creates a new BaseCallback instance with default settings
func NewBaseCallback() *BaseCallback {
	return &BaseCallback{
		DefaultTimeout: 30 * time.Second,
		LogEnabled:     true,
	}
}

// OnNotify implements RPCCallback.OnNotify with basic logging
func (b *BaseCallback) OnNotify(session *RPCSession, msg *RPCMessage) {
	if b.LogEnabled {
		fmt.Printf("Notification received: method=%s, session=%d\n",
			msg.GetMessageID(), session.GetID())
	}
}

// OnRequest implements RPCCallback.OnRequest with error response
func (b *BaseCallback) OnRequest(session *RPCSession, inMsg *RPCMessage, outMsg *RPCMessage, timeout time.Duration) error {
	if b.LogEnabled {
		fmt.Printf("Request received: method=%s, session=%d\n",
			inMsg.GetMessageID(), session.GetID())
	}
	return ErrNotImplemented
}

// OnConnect implements RPCCallback.OnConnect with basic logging
func (b *BaseCallback) OnConnect(session *RPCSession) {
	if b.LogEnabled {
		fmt.Printf("Session connected: id=%d\n", session.GetID())
	}
}

// OnClose implements RPCCallback.OnClose with basic logging
func (b *BaseCallback) OnClose(session *RPCSession, errorCode int, errorMsg string) {
	if b.LogEnabled {
		if errorCode != 0 {
			fmt.Printf("Session closed with error: id=%d, code=%d, msg=%s\n",
				session.GetID(), errorCode, errorMsg)
		} else {
			fmt.Printf("Session closed: id=%d\n", session.GetID())
		}
	}
}
